Unix/Linux/GNU Linux
Linux本质是指 Linux 内核,而GNU/Linux则代表这是一个发行版系统(内核+GNU工具), GNU的全称又是:Gnu’s Not Unix, 本质上这些都属于类unix系统。
bash配置文件(Linux or Mac)
全局配置文件
- /etc/profile 和 /rtc/profile.d/*.sh : 此文件为系统的每个用户设置环境信息,当用户第一次登录时该文件被执行,并从/etc/profile.d目录的配置文件中搜集shell的设置
- /etc/bashrc : 为每一个运行bash shell的用户执行此文件,当bash shell被打开时,该文件被读取
个人配置文件
- ~/.bash_profile : 每个用户都可使用该文件输入专用于自己使用的shell信息;当用户登录时,该文件仅仅执行一次;默认情况下,他设置一些环境变量,执行用户的.bashrc文件
- ~/.bashrc : 该文件包含专用于你的bash shell的bash信息,当登录时以及每次打开新的shell时,该文件被读取
- ~/.bash_history :
- ~/.bash_logout : 当每次退出系统(退出bash shell)时,执行该文件
shell如何读取配置文件
登录式shell如何读取配置文件
/etc/profile --> /etc/profile.d/*.sh --> ~/.bash_profile --> ~/.bashrc --> /etc/bashrc
非登录式shell如何配置文件
~/.bashrc --> /etc/bashrc --> /etc/profile.d/*.sh
配置变量和命令
$PATH : 决定了shell将到哪些目录中寻找命令或程序,PATH的值是一系列目录,当您运行一个程序时,Linux在这些目录下进行搜寻编译链接
# 设置PATH, PATH N 为自己加上指定路径,中间用冒号隔开 $ PATH=$PATH:PATH1:PATH 2:PATH 3: ... :PATH N # 打印当前搜索路径的两种方法 $ echo $PATH 或者 $ export # 打印全局变量的两种方法,printenv HOME打印变量值 $ env 或者printenv # 显示所有的全局变量,局部变量以及用户自定义变量 $set
export : 该命令将新变量添加到环境中 ; 在命令行直接执行可以设置一个新的临时环境变量, 变量在关闭shell时失效
- source .bash_profile : 使设置的PATH生效
- 每次重新打开终端的时候,.bashrc会自动执行一次,而.bash_profile不会
shell和shell脚本的概念
shell是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。Ken Thompson的sh是第一种Unix Shell,Windows Explorer是一个典型的图形界面Shell。
shell脚本(shell script),是一种为shell编写的脚本程序。业界所说的shell通常都是指shell脚本,但读者朋友要知道,shell和shell script是两个不同的概念。本文出现的“shell编程”都是指shell脚本编程,不是指开发shell自身(如Windows Explorer扩展开发)
脚本解释器
sh —- 即Bourne shell,POSIX(Portable Operating System Interface)标准的shell解释器,它的二进制文件路径通常是/bin/sh,由Bell Labs开发。
Bash —- 是Bourne shell的替代品,属GNU Project,二进制文件路径通常是/bin/bash。
ksh、csh、zsh等不常用的解释器
shell脚本实例
#!/bin/sh
cd ~
ret=`mkdir shell_tut`
cd shell_tut
for ((i=0; i<10; i++)); do
touch test_$i.txt
done
- 定义变量时,变量名不加美元符号($)
- 变量名和等号之间不能有空格
- 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;单引号字串中不能出现单引号(对单引号使用转义符后也不行)
- 双引号里可以有变量,双引号里可以出现转义字符
- 以“#”开头的行就是注释,会被解释器忽略
- bash shell提供了一个组合键来生成 EOF(End-of-File)字符。Ctrl+D组合键会在bash中产生一个EOF字符
shell并发多进程执行
命令之后加入 &可以让for循环中的命令并行执行,添加wait可以保证for循环所有命令执行完后再向后执行接下来的命令
1 | #!/bin/bash |
运行Shell脚本的两种方法
chmod +x test.sh
./test.sh
或者
bin/sh test.sh
/bin/php test.php
第一种必须要带上.才能在当前目录寻找脚本,否则会去PATH寻找;第二种不需要指定#!/bin/sh
Shell日志分析常用命令
查看内容
who - show who is logged on # 多个命令可以用分号隔开,同时执行 who; date # 通配符?代表一个字符,*代表多个字符 ls -alh ll a*.txt ll a?.txt # 符号链接(软链接):指向源文件的新的独立文件(类似于一个新指针),与原文件完全不同,inode也不同,但是读写起来就像原始文件一样 ln -s a a_link # 硬链接:与原文件本质上是同一个文件,大小一样,修改时间一样,只是在目录下的文件名不一样 # 不管硬链接还是软链接,修改都会影响到原文件 ln a a_link # 查看inode编号 ls -li a* # 查看目录的树形结构 tree dir # 查看文件内容,显示行数和进度; 输入v可以直接进入vim编辑模式 less -NM file # cat新建、合并文件 cat > file cat f1 f2 > f # 显示行数 cat -n/-b file # 使用两个 > 符时, 会将第一个文件中的内容追加到第二个文件的末尾 cat /root/linux >> /root/desktop # ps,top,du,df查看系统信息 lsblk -f: 可以查看未挂载的文件系统类型 parted -l 命令会输出文件系统类型(File system), 其中参数l表示列出所有设备的分区信息 parted /dev/sdg fdisk -l df -T 查看已经挂载的分区和文件系统类型 killall a* 杀死所有以a开头的进程 mount 查看系统挂载的设备列表 umount 卸载设备 # 测试url联通性 wget -nv --spider $url
数据提取处理
# sort -n可以识别每行开头的数字,并按其大小对文本行进行排序;-t设置分隔符 # sort默认是按升序排列,如果想要按降序要加-r选项(sort -rn), sort命令按照第1个、第2个、第N个字段依次排序,如果第一个字段相同,就按第2个字段的顺序排列,直到最后。 # 用命令cut -c 9- 取出每行第9个及其以后的字符 # uniq命令只能对相邻行进行去重操作,所以要先sort;uniq -c显示每一行出现次数,-u只显示单独出现的行,-d只显示重复出现的行 # 排序+去重并显示次数+按开头数字降序+取出第9个之后的字符 sort file | uniq -c | sort -rn | cut -c 9- # 先对第2列sort,然后对第3列sort sort t.txt -k2,2n -k3,3n # 对sort_*多个已经排好序的文件做merge并去重,得到排序不重复的文件 sort -smu sort_* # grep或操作 grep 'word1\|word2' grep -E 'word1|word2' grep -E "2017:22:5[0-9]" 查找时间在2017:22:50~2017:22:59所在的行 grep -E "[5-8][6-9][0-3]" 查找大于560小于893的行 grep -E "^$" file 查找file文件中的空行 grep -E "^[^w]" file 查找文件中不是以w开头的行 grep -10 'abc' test.log 打印匹配行的前后10行 grep -A 10 '123' test.log 打印匹配行的后10行 grep -B 10 '123' test.log 打印匹配行的前10行 tac file | grep -m 1 foo 找到file中最后1个匹配foo的行, 适合大文件 awk '/foo/{k=$0}END{print k}' file 等价 # 非操作 grep -v 'word1\|word2' # grep正则匹配 grep -o regex FILENAME 正则匹配 # 例如匹配vip=ip地址形式文本 grep -o 'vip=[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' grep -n pattern file 显示行号 grep -c pattern file 显示匹配到的行数 # 压缩文件相关的搜索 zgrep "/api" access_log.gz access_log_1.gz zcat access.tar.gz | grep -a '/api' zgrep -a "/api" access.tar.gz zcat 解压文件并将内容输出到标准输出 zcmp 解压文件并且 byte by byte 比较两个文件 zdiff 解压文件并且 line by line 比较两个文件 zgrep 解压文件并且根据正则搜索文件内容 # 根据进程路径查找pid并kill kill `ps -ef | grep bos/nginx | grep master | awk '{print $2}'` # 去除每一行中的重复空格,输出 'a b c' echo 'a b c' | tr -s ' ' # 数学表达式,例如计算10*10的结果, 只支持整数运算 echo $[10*10] expr 5 / 2 不支持浮点数计算 echo 'scale=3;5/2' | bc # bc进入计算器模式,可以进行浮点数运算,scale=4代表保留4位小数,quit退出
cut:按行剪切数据,cut命令主要是接受三个定位方法: ①字节(bytes),用选项-b,例如; ②字符(characters),用选项-c; ③域(fields),用选项-f; -n选项,-n用于告诉cut不要将多字节字符拆开
# 提取每一行的第3个字节,-3表示从第一个字节到第三个字节,而3-表示从第三个字节到行尾 cat file | cut -b 3 # 提取每一行的第3,4,5,8个字节,执行此命令时,cut会先把-b后面所有的定位进行从小到大排序 cat file | cut -b 3-5,8 # -d来设置间隔符为空格,然后用-f来设置我要取的是第一个域(用awk也可以取出指定列) cat file | cut -d ' ' -f 1 # cut的-d选项的默认间隔符就是制表符,当要使用制表符的时候,可以省略-d选项,直接用-f来取域;cut -d只允许间隔符是一个字符。
sed:一种流编辑器,会在编辑器处理数据之前基于预先提供的一组规则来编辑数据流。sed按行处理文本,默认从STDIN读取文本并将处理结果输出到STDOUT,不改变输入文本内容。
# 显示空格和制表符的区别,-n选项是禁止编辑器输出,l是将特殊符以直观形式输出 sed -n l file # sed 替换字符串,把文本中第一个dog替换成big cat echo "This is a dog" | sed 's/dog/big cat/' # 删除前N个字符 sed -i 's/^..//' file (N个.表示N个字符) # substitute替换,通用格式:s/pattern/replace/flags, 选项可以是g,p,w,数字 sed 's/dog/big cat/g' data.txt # -n + p 等价于w选项,只输出被替换命令修改过的行 # 包含特殊字符/的字符串替换,可使用\转义或者指定分隔符! sed 's!/bin/bash!/bin/csh!' /etc/passwd sed 's/\/bin\/bash/\/bin\/csh/' /etc/passwd # -e执行多条命令到每行数据上 sed -e 's/brown/green/; s/dog/cat/' data1.txt # -f选项读取script1.sed文件中所有sed命令并执行,每行都是一条单独的命令 sed -f script1.sed data1.txt # sed行寻址,也就是讲命令只作用于特定行or某些行 sed '2s/dog/cat/' data1.txt sed '2,3s/dog/cat/' data1.txt # 只作用于第2行到最后一行 sed '2,$s/dog/cat/' data1.txt # 只作用于包含Samantha的行 sed '/Samantha/s/bash/csh/' /etc/passwd # sed删除行 sed '2,3d' data1.txt # 只作用于第2行到最后一行 sed '2,$d' data1.txt # 删除第一行 tail -n +2 file # 只作用于包含Samantha的行 sed '/Samantha/d' /etc/passwd # 插入行, 最后一行之后插入 sed '$a\This is a new line of text.' data1.txt # 第三行之前插入 sed '3i\This is a new line of text.' data1.txt # 修改包含'number 3'内容的行 sed '/number 3/c\ > This is a changed line of text.' data6.txt # 修改第3行 sed '3c\ > This is a changed line of text.' data6.txt # sed transform转换命令会对inchars和outchars值进行一对一的映射 $ echo "This 1 is a test of 1 try." | sed 'y/123/456/' This 4 is a test of 4 try. # 禁止输出其他行,只打印包含匹配文本模式的行 sed -n '/number 3/p' data6.txt # 非操作! sed -n '/number 3/!p' data6.txt 提取内容并写入文件 # 将data6.txt数据流中的前两行打印到一个文本文件test.txt中 sed '1,2w test.txt' data6.txt # 只将包含文本模式的数据行写入目标文件Browncoats.txt sed -n '/Browncoat/w Browncoats.txt' data11.txt 从文件读数据 # 读取data12.txt所有内容,并写入data6.txt文件第三行之后 sed '3r data12.txt' data6.txt # 写入包含number 2的一行之后并删除number 2行 sed '/number 2/r data12.txt' data6.txt sed '$r data12.txt d' data6.txt # sed多行命令 # next,n命令会让sed编辑器移动到文本的下一行 # N命令将下一行合并到当前行 sed '/first/{ N ; s/\n/ / }' data2.txt # 合并行号和行内容 sed '=' data2.txt | sed 'N; s/\n/ /' # 向文本文件的行间插入空白行 sed 'G' data2.txt # 删除连续的空白行,保留单个空白行 sed '/./,/^$/!d' data8.txt # 用排除符号(!)和尾行符号($)来确保脚本不会将空白行加到数据流的最后一行后面 sed '$!G' data2.txt
awk: gawk程序是Unix中的原始awk程序的GNU版本。gawk程序让流编辑迈上了一个新的台阶,它提供了一种编程语言而不只是编辑器命令。awk是一种文本处理和模式匹配语言,数据驱动的语言。gawk程序脚本用一对花括号来定义,你必须将脚本命令放到两个花括号{}中
# 强制awk在读取数据前执行BEGIN关键字后指定的程序脚本;END关键字允许你指定一个程序脚本,awk会在读完数据后执行它 awk 'BEGIN {print "Hello World!"}' # awk默认以任意的空白字符(例如空格或制表符)分割每一行,也可以用-F指定分隔符(也可以定义FS的特殊变量来指定字段分隔符),$0代表整行,$n代表第n列内容 # 打印file的第五列 cat file | awk '{print $5}' awk -F: '{print $1}' file # 通过设置OFS变量,可以在输出中使用任意字符串来分隔字段 # 以,为分隔符,读取1-3列,然后以-连接,输出;相当于替换分隔符 awk 'BEGIN{FS=","; OFS="-"} {print $1,$2,$3}' data1 # 记录分隔符设置,例如把文件中的每行都当成一个字段,把空白行当作记录分隔符,可以起到合并多行成1行的效果 awk 'BEGIN{FS="\n"; RS=""} {print $1,$4}' data2 # awk自带的ARGC,ARGV,NF,FNR等数据变量 # awk自定义变量,进行计算 awk 'BEGIN{x=4; x= x * 2 + 13 % 2 + 3^2; print x}' # awk 遍历数组变量 gawk 'BEGIN{ > var["a"] = 1 > var["g"] = 2 > for (test in var) >{ > print "Index:",test," - Value:",var[test] >}' # awk 匹配操作符/……/,例如筛选出包含11的行做对应处理,用逗号做分隔符 gawk 'BEGIN{FS=","} /11/{print $1}' data1 # 在每行第一个数据字段中查找以文本rich开头的行,打印第一个和最后一个字段 awk -F: '$1 ~ /^rich/{print $1,$NF}' /etc/passwd # 非操作! gawk –F: '$1 !~ /^rich/{print $1,$NF}' /etc/passwd # 数学表达式,==,<=…… gawk -F, '$1 == "data"{print $1}' data1 # awk使用if else,while,for等结构化语句 awk '{if ($1 > 20) print $1 * 2; else print $1 / 2}' data4 # printf格式化输出,例如用几个单独的printf命令在同一行上打印多个输出 gawk 'BEGIN{FS=","} {printf "%s ", $1} END{printf "\n"}' data1 # rand()产生随机数只在0和1之间(不包括0或1),int会生成该值和0之间最接近该值的整数 x = int(10 * rand()) # 字符串函数,时间函数,自定义函数 # 在定义函数时,它必须出现在所有代码块之前(包括BEGIN代码块),例如 awk ' > function myprint() > { > printf "%-16s - %s\n", $1, $4 > } > BEGIN{FS="\n"; RS=""} > { > myprint() > }' data2 # 也可以把函数定义到文件中,然后用-f引用函数 # 求sum和average,使用awk变量时不需要带$ cat file | awk '{sum+=$1} END {print "Sum = ", sum}' cat file | awk '{sum+=$1} END {print "Average = ", sum/NR}' # a.txt中每一行为一个单词,按行读取a.txt, $1代表第一列,统计出出现次数前3名的单词 # sort -n -r -k 2 -t ':' xx.txt -n数字排序方式, -r倒序, -t ':'以冒号分隔, -k 2表示以冒号分隔后的第2列 awk '{sum[$1]+=1} END {for(k in sum) print k ":" sum[k]}' a.txt | sort -n -r -k 2 -t ':' | head -n 3 # awk对文件行内容去重,O(n)时间复杂度,利用了hashtable数据结构 awk '!seen[$0]++' file # 对这个文件的每一行进行检查,如果你之前没有见过它,就打印出来,$0 是一个变量,表示整个当前行 awk '{ if (!seen[$0]++) { print $0; } }'
权限相关(Linux文件权限以八进制表示)
umask 设置文件(666-x)or目录(777-x)默认权限的掩码 权限的八进制表示:wr- --> 110 --> 6 # 八进制修改权限 chmod -R 777 dir chmod 777 file #符号模式修改权限 chmod u+w file 给文件user增加write权限 # 改变文件的属主和属组;只有root可以改变文件属主,任何属主可以改变属组 chown user.group file
处理脚本控制信号和特殊参数
默认情况下,脚本以最后一个命令的退出状态码退出;当然也可以通过
0```来指定退出状态码,范围为0-255,如果大于255,则以num % 256返回给用户 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 输出上一命令的退出码
echo $?
# shell的位置参数变量是标准的数字:$0是程序名,$1是第一个参数,$2是第二个参数,依次类推,直到第九个参数$9
# $0参数获取shell在命令行启动的脚本名
echo $0
# basename获取绝对路径下的文件名or文件夹名
echo $(basename $0)
# 定时任务
cron,crontab,anacron和at
# 进程优先级调度
nice和renice
# 后台前台任务:jobs -l,bg,fg,&,nohup
#### Linux/Mac常见目录
1. /bin 存放系统管理员和普通用户都要使用的程序
2. /sbin 存放用于系统恢复,系统启动,系统维护等程序
3. /usr/bin 登录用户可以使用的预装程序一般都放在这里,会随着系统升级而改变
4. /usr/share/bin 可以通过web访问的程序一般放在这里
5. /usr/local/bin 目录是给用户放置自己的可执行程序的地方,是手动编译或者安装的程序, 不会被系统升级而覆盖同名文件
6. usr 指 Unix System Resource,而不是User
7. /lib目录都是为/bin, /sbin准备的;一个应用程序启动的时候,会在/lib 和 /usr/lib库中查找动态库
#### [Linux常用的查找命令](http://www.ruanyifeng.com/blog/2009/10/5_ways_to_search_for_files_using_the_terminal.html)
find/locate, whereis/which/ps -ef, grep
* find文件查找:`find path_name -name file_name -exec rm -f {} \;`
`find / -name '*abvd*'` 查找包含abvd字符串的文件名文件
* grep搜索目录和子目录: `grep -R '文本' ./*`
* whereis定位可执行文件位置
#### 其它命令
1. **rsync**是远程和本地在Linux / Unix系统中复制和同步文件和目录的最常用命令
* 用法```rsync options source destination- 优势:rsync能有效地将文件复制到远程系统或从远程系统同步到本地,支持复制链接,设备,所有者,组和权限;相对于scp命令,rsync使用远程更新协议,允许转让只是两套文件之间的差异。 第一次,它从源到目标复制文件或目录的整个内容,但从下一次,它只将已更改的块和字节复制到目标。rsync消耗更少的带宽 ,因为它使用压缩和解压缩方法在发送和接收数据两端。更加安全,可以使用scp、ssh等方式来传输文件,当然也可以通过直接的socket连接,还支持匿名传输。
案例:
/* -v:详细
-r:将数据递归(但不保存时间戳和权限,同时传输数据
-a:—archive归档模式下,归档模式允许递归地拷贝文件,同时也保留了符号链接,文件权限,用户组所有权和时间戳等所有文件属性,等于-rlptgoD
-z:压缩文件中的数据
-h:在人类可读的格式人类可读,输出数字
-progress 选项。 它显示完成传输的文件和剩余时间。
-e ssh 指定ssh协议传输
—remove-source-files 成功传输后自动删除源文件
*/ // 拷贝本地文件。当SRC和DES路径信息都不包含有单个冒号":"分隔符时就启动这种工作模式 rsync -a ./test.c /backup //用一个远程shell程序(如rsh、ssh)来实现将本地机器的内容拷贝到远程机器,当DES路径地址包含单个冒号":"分隔符时启动该模式 rsync -avz test.c user@172.16.0.11:/home/user/src // 用一个远程shell程序(如rsh、ssh)来实现将远程机器的内容拷贝到本地机器 rsync -avz user@172.16.0.11:/home/user/src ./src // 从远程rsync服务器中拷贝文件到本地机。当SRC路径信息包含"::"分隔符时启动该模式 rsync -av user@172.16.0.11::www /databack // 从本地机器拷贝文件到远程rsync服务器中。当DES路径信息包含"::"分隔符时启动该模式 rsync -av /databack user@172.16.0.11::www //列远程机的文件列表 rsync -v rsync://172.16.78.192 /www
对当前目录下所有文件夹添加读写权限:
1
2chmod -R 777 * 或者chmod -R 777 .
chown -R a:b:c * 修改ower, group, others-
1
2
3
4
5
6
7
8
9
10
11
12
13jobs –l 查看后台运行的进程
fg %n 让后台运行的进程n到前台来
bg %n 让进程n到后台去
暂停程序运行CTRL+Z
kill %n 杀死进程n
ls -la | grep php 查看php真实路径
```
4. `tar zcvf /home/httpd/html/CAP-IDA/tmp.tar.gz -C /home/httpd/html/CAP-IDA/Data IDASUBSTAT` 绝对路径压缩文件夹IDASUBSTAT,使用-C指定相对路径去除多余层次
5. Linux taskset命令和sched_setaffinity函数将某个进程绑定到一个特定的CPU
#### Linux小技巧
1. 生成随机密码的两种方式:① `date | md5 | cut -b -8` ② `openssl rand -base64 8`
2. **随机生成10个8位密码shell脚本**: 首位大写字母, 中间六位大小写字母数字随机混合, 第八位[0-9]
!/bin.bash
for i in {1..10}
do
A=head -c 500 /dev/urandom | tr -dc A-Z |head -c 1
随机生成500字符|只取大写字母|取第一个字符
B=head -c 500 /dev/urandom | tr -dc [:alnum:]| head -c 6
随机生成500字符|取英文大小写字节及数字,亦即 0-9, A-Z, a-z|取6位
C=echo $RANDOM$RANDOM|cut -c 2
取第二位随机数字,第一位随机性不高大多数是1或2,所以取第二位.
echo $A$B$C
done1
2
3
4
5
6
7
8
9
3. `source /path/to/filename` 在当前 shell 里执行一个文件里的命令
4. `wget -r --no-parent --reject "index.html*" http://hostname/ -P /home/user/dirs` 用 wget 抓取完整的网站目录结构,存放到本地目录中
5. diff和cmp命令,分别比对两个file的逐行和逐字节
6. [Shell 前后台进程切换](https://cnbin.github.io/blog/2015/06/15/shell-qian-hou-tai-jin-cheng-qie-huan/)
7. `dd if=/dev/zero of=obj_900k bs=1024 count=0 seek=$[9*1024/10]` 生成900k的文件
8. `mv /usr/cbu/ * .` 将/usr/cbu中的所有文件移到当前目录(用“.”表示)中
9. `at -f data 15:30 +2 days` 让系统在两天后的17:30执行文件data中指明的作业
10. 统计单机QPS
awk ‘{print $2}’ access.log | cut -c12-19 | sort | uniq -c | sort -nr| less
实时
tail -f access.log | awk -F ‘[‘ ‘{print $2}’ | awk ‘{print $1}’ | uniq -c
```